﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Description;
namespace Justin.Wcf.Hosting
{
    class Program
    {
        static void Main(string[] args)
        {
            
            #region Hosting a service using managed code without any configuraiton information.

            //comments from the App.config before runing the following code and comment web.config , app.config in service project.

            /* 
             WCF提供了两种元数据发布方式：
             1. HTTP-GET：则仅适用于HTTP,要显式的添加服务行为(Behavior)功能。。
             2. MEX终结点：WCF的标准发布方式，支持所有绑定。
            */

            #region Publish metadata based on HTTP-GET

            //using (ServiceHost host = new ServiceHost(typeof(Justin.Wcf.Services.CalculatorService), new Uri("http://localhost:8000/CalculatorService/")))
            //{
            //    // 检查配置文件中是否配置过behavior
            //    if (host.Description.Behaviors.Find<ServiceMetadataBehavior>() == null)
            //    {
            //        ServiceMetadataBehavior behavior = new ServiceMetadataBehavior();
            //        behavior.HttpGetEnabled = true;

            //        //HttpGetUrl属性用来获取元数据，如果不设置改属性只能通过基地址+wsdl的方式获取
            //        behavior.HttpGetUrl = new Uri("http://localhost:8000/CalculatorService/metadata");
            //        host.Description.Behaviors.Add(behavior);
            //    }

            //    //Add Endpoint
            //    host.AddServiceEndpoint(typeof(Justin.Wcf.Services.ICalculator), new WSHttpBinding(), "");
            //    // Setting Timeout 10
            //    host.CloseTimeout = TimeSpan.FromSeconds(10);

            //    host.Open();
            //    Console.WriteLine("Service has been started");
            //    Console.Read();
            //    host.Close();

            //}

            #endregion

            #region Publish metadata based on MEX endpoint
            //using (ServiceHost host = new ServiceHost(typeof(Justin.Wcf.Services.CalculatorService), new Uri("net.tcp://localhost:9000/")))
            //{
            //    host.Description.Behaviors.Add(new ServiceMetadataBehavior());
            //    host.AddServiceEndpoint(typeof(Justin.Wcf.Services.ICalculator), new NetTcpBinding(), "CalculatorService");

            //    /*
            //     * 该例子中我们使用TCP协议因此只能使用 MEX终结点发布元数据 xxxxx 这句话是错的。也可以使用HTTP--Get
            //     * NetTcpBinding只能通过MEX终结点发布元数据。关于元数据地址，这里添加了一个MexTcpBinding绑定类型的endpoint，
            //     * 它就承担为整个service对外提供元数据的任务，因此上面的endpoint中的相对地址(CalculatorService)将被忽略.
            //     */

            //    host.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexTcpBinding(), "mex");
            //    host.Open();
            //    Console.WriteLine("Service has started");
            //    Console.Read();
            //    host.Close();
            //}
            #endregion

            #region Hosting multiple services in one process and each service has multiple base address.
            /*
             *  
             * 需要理清楚的是。发布方式，基地址，终结点之间的关系。
             * 
             *  1. HTTP-GET：则仅适用于HTTP,要显式的添加服务行为(Behavior)功能。并不能保证所有平台都支持该方式。
             *  2. MEX终结点：WCF的标准发布方式，支持所有绑定。
             *  
             * 使用HTTP-GET方式发布元数据，必须要为服务注册一个HTTP基地址, 当客户端请求该HTTP地址是元数据将以XML的形式返回。
             * 
             * 这里需要注意的是：“必须要为服务注册一个HTTP基地址”深刻理解这句话的隐喻：
             * 
             * 意思不是说只能通过HTTP与服务端互交 或者说 发布的元数据中只包含绑定类型为HTTP的Endpoint，而是说只能通过HTTP协议来获取元数据。
             * 元数据时一个消息描述了如何与服务端互交(也就是说是如果与服务器互交的详细信息列表，客户端拿到这个列表后还有很多事情要干，例如生成代理类等等)，
             * 客户端与服务端互交是通过元数据中的Endpoint 描述，数据描述，Service描述 生成代理类，通过代理类与Service互交。
             * 
             * 举例子：假设,一我定义了一个服务CalculatorService它仅有一个类型为net.tcp的基地址 和一个 绑定类型为NetTcpBinding的终结点
             * 现在我要将它的元数据发布出去。
             * 我第一个想到的是MEX终结点方式。因为它仅有一个类型为net.tcp的基地址。如果想用HTTP-GET方式发布该元数据我们该如何做？
             * 
             * 1. 为该服务添加一个HTTP基地址，
             * 2. ServiceMetadataBehavior 对象的 HttpGetEnabled属性设置为True
             * 
             * 因此HTTP-GET与MEX终结点可以发布任何绑定类型的类型的元数据，只是获取这两种方式发布的元数据的方式有些不同。对于HTTP-GET
             * 方式发布的元数据，只能通过HTTP协议获取该元数据。而对于使用MEX终结点方式发布的数据，我们可以通过发布所使用的协议来获取元数据。
             * 而MEX终结点方式发布的数据可以使用任何协议，因为我们也可以说我们可以使用任何协议来获取MEX发布的元数据。
             * 
             * 
             * 发布方式，基地址，终结点之间的关系
             * 
             * 对于HTTP-GET方式发布的服务元数据，该服务必须包含一个HTTP协议的基地址(客户端依赖于该HTTP基地址获取元数据), 
             * 该服务可以包含多个任意绑定类型的终结点。HTTP-GET发布的元数据将包含这些不同绑定类型的Endpoint描述。以便客户端
             * 生成代理类。
             * 
             * 对于MEX终结点方式发布元数据：基地址的Schema，终结点的绑定类型，以及MEX终结点的绑定类型类型必须一致。
             * 我们知道每个服务终结点必须有一个基地址与之对应(基地址 net.tcp://localhost/ 对应的绑定为：NetTcpBinding)，
             * 问题是是否一个每一个服务终结点都必须有一个MEX终结点与之对应呢？ 待验证.....
             */

<<<<<<< .mine
            ServiceHost calculatorServiceHost = new ServiceHost(typeof(Justin.Wcf.Services.CalculatorService), 
                                                                                                new Uri("net.tcp://localhost:8001/"),
                                                                                                new Uri("http://localhost:8002/"));
=======
            //ServiceHost calculatorServiceHost = new ServiceHost(typeof(Justin.Wcf.Services.CalculatorService), 
            //                                                                                    new Uri("net.tcp://localhost:8001/"),
            //                                                                                    new Uri("http://localhost:8002/"));
>>>>>>> .r306

<<<<<<< .mine
            ServiceHost printerServiceHost = new ServiceHost(typeof(Justin.Wcf.Services.PrinterService),
                                                                                                new Uri("net.tcp://localhost:8003/"),
                                                                                                new Uri("http://localhost:8004/"));
=======
            //ServiceHost printerServiceHost = new ServiceHost(typeof(Justin.Wcf.Services.PrinterService),
            //                                                                                    new Uri("net.tcp://localhost:8003/"),
            //                                                                                    new Uri("http://localhost:8004/"));
>>>>>>> .r306

            if (calculatorServiceHost.Description.Behaviors.Find<ServiceMetadataBehavior>() == null)
            {
                ServiceMetadataBehavior behavior = new ServiceMetadataBehavior();
                behavior.HttpGetEnabled = true;
                behavior.HttpGetUrl = new Uri("http://localhost:8002/metadata");
                calculatorServiceHost.Description.Behaviors.Add(behavior);
            }

            //if (printerServiceHost.Description.Behaviors.Find<ServiceMetadataBehavior>() == null)
            //{
            //    ServiceMetadataBehavior behavior = new ServiceMetadataBehavior();
            //    behavior.HttpGetEnabled = true;
            //    behavior.HttpGetUrl = new Uri("http://localhost:8004/metadata");
            //    printerServiceHost.Description.Behaviors.Add(behavior);
            //}
<<<<<<< .mine

            calculatorServiceHost.Description.Behaviors.Add(new ServiceMetadataBehavior());
            printerServiceHost.Description.Behaviors.Add(new ServiceMetadataBehavior());

=======

>>>>>>> .r306
            //calculatorServiceHost.AddServiceEndpoint(typeof(Justin.Wcf.Services.ICalculator), new WSHttpBinding(), "");
<<<<<<< .mine
            calculatorServiceHost.AddServiceEndpoint(typeof(Justin.Wcf.Services.ICalculator), new NetTcpBinding(), "");
            calculatorServiceHost.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexHttpBinding(), "MEX");
=======
            //calculatorServiceHost.AddServiceEndpoint(typeof(Justin.Wcf.Services.ICalculator), new NetTcpBinding(), "");
            //calculatorServiceHost.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexTcpBinding(), "MEX");
>>>>>>> .r306

            //printerServiceHost.AddServiceEndpoint(typeof(Justin.Wcf.Services.IPrinter), new WSHttpBinding(), "");
            //printerServiceHost.AddServiceEndpoint(typeof(Justin.Wcf.Services.IPrinter), new NetTcpBinding(), "");
            //printerServiceHost.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexTcpBinding(), "MEX");

<<<<<<< .mine

            calculatorServiceHost.Open();
            printerServiceHost.Open();
=======
            //calculatorServiceHost.Open();
            //printerServiceHost.Open();
>>>>>>> .r306

            //Console.Read();

            //calculatorServiceHost.Close();
            //printerServiceHost.Close();
            #endregion

            #endregion

            #region Self-Hosting via configuration

            //remove comments from the App.config before runing the following code 

            ServiceHost calculatorHost = new ServiceHost(typeof(Justin.Wcf.Services.CalculatorService));
            ServiceHost printerHost = new ServiceHost(typeof(Justin.Wcf.Services.PrinterService));

            calculatorHost.Open();
            printerHost.Open();

            Console.WriteLine("Service has been started");
            Console.ReadKey();

            calculatorHost.Close();
            printerHost.Close();

            #endregion
        }
    }
}
